#include <iostream>

#include "yaml-cpp/yaml.h"

#include "../net/TcpServer.h"
#include "../net/http/HttpResponse.h"
#include "../net/http/HttpRequest.h"
#include "../base/log/Logging.h"
#include "../base/log/AsyncLogging.h"
#include "../database/ConnectionPool.h"
#include "../net/http/HttpServlet.h"

#define OUT std::cout
#define END std::endl

/* 配置数据库连接池 */
ConnectionPool *pool;

/* 下面是日志相关的配置 */
AsyncLogging *g_asyncLog = nullptr;

void asyncOutput(const char *msg, int len) {
    g_asyncLog->append(msg, len);
}

/* 下方是数据库连接池相关配置 */
/**
 * 初始化数据库连接池
 * @param num 链接池链接数量
 */
void initConnectionPool(ConnectionPool *pool_);

/* 初始化日志相关 */
void initLog(AsyncLogging *log);

/* 下方是httpServlet测试相关*/
void doLogin(const HttpRequest & req, HttpResponse * resp){
    resp->addHeader("Content-Type", "application/json");
    resp->setStatusMessage("SUCCESS");
    resp->setStatusCode(HttpResponse::k200Ok);
    string username;
    string password;
    if(!req.getBodyCheckAs<string>("username", username) || !req.getBodyCheckAs("password", password)){
        resp->setBody("{\"msg\":\"用户名或密码错误\",\"code\":201}");
        return;
    }else{
        if(username == "lin" && password == "123456"){
            resp->addHeader("Authorization",
                            "Bearer eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoie1wiaWRcIjoxLFwidXNlcm5hbWVcIjpcImxpblwiLFwicGFzc3dvcmRcIjpudWxsfSIsImp0aSI6IjEifQ.Qjz1_xJN6qprhAOYMTjdogadjUGJWDRShTl7vj9F2GDl_x6U_PijmHVKQa4Byb9gQ6CndSGMUyjs2CFZmLPunNuzhZdNtMyNkkNd4vtgw03RGuRTtq2Rp4m3fE58OjYsTzmRiOU4O4mTs6W2nYckuKurKUSw90LqwU1nYGFOE3BhfjBvRpTu_k3iUJN2GBgifH2J0NQ3Hc58NgVEPa5nW7U72yx7Yiy2yjXmz2F3usXifrYZFWNZlb6ERUJVIFeinIXlOSCAcdDR3J_Zx3ka_s7tyAsNEoorXcI8ctpap61vm-yYFIU7AdS7CHzVSJ2Tpi-shO16Gy_tnmE1P20ALQ");
            resp->setBody("{\"msg\":\"认证通过!\",\"code\":200}");
            return;
        }else{
            resp->setBody("{\"msg\":\"用户名或密码错误\",\"code\":201}");
            return;
        }
    }

}

void viewRequest(const HttpRequest & req){
    std::stringstream os;
    os << "request path: " << req.getPath() << std::endl;
    os << "http version: " << req.getVersion() << std::endl;
    os << "http headers: " << std::endl;
    auto headers = req.headers();
    for(const auto & item : headers){
        os << item.first << ":" << item.second << std::endl;
    }
    os << "request body" << std::endl;
    for(const auto & item : req.body()){
        os << item.first << ":" << item.second << std::endl;
    }
}

/* 下方是初始化yaml并读取部分 */
void initFromYaml(){
    YAML::Node config;
    try {
        config = YAML::LoadFile("../config/application.yaml");
        // 读取配置文件
    } catch (YAML::BadFile &e) {
        LOG_FATAL << "读取配置文件失败";
    }

    // 初始化日志部分
    YAML::Node logConfig = config["log"];
    string basename = logConfig["basename"].as<string>();
    off_t kRollSize = logConfig["kRollSize"].as<off_t>();
    int flushInterval = logConfig["flushInterval"].as<int>();
    AsyncLogging log(basename, kRollSize, flushInterval);
    initLog(&log);

    YAML::Node databaseConfig = config["database"];
    int numConnections = databaseConfig["numConnections"].as<int>();
    string database = databaseConfig["databaseName"].as<string>();
    string username = databaseConfig["username"].as<string>();
    string password = databaseConfig["password"].as<string>();
    string host = databaseConfig["host"].as<string>();
    int port = databaseConfig["port"].as<int>();
    ConnectionPool pool_(numConnections,
                         database,
                         username,
                         password,
                         host,
                         port);
    initConnectionPool(&pool_);

    HttpServlet server(8200, 10);
    server.updateCallback("/sys/login", doLogin);
    server.run();
    /* 配置单例模式servlet, 自动初始化EventLoop并在run的时候启动函数*/
}

int main(){
    LOG_INFO << "main() start ~ ";
    initFromYaml();
}

/* 初始化日志相关 */
void initLog(AsyncLogging *log) {
    // 每 1s 刷盘一次
    Logger::setOutput(asyncOutput);
    Logger::setIsAsync(true);
    Logger::setLogLevel(Logger::LogLevel::DEBUG);
    g_asyncLog = log;
    log->start();
    LOG_INFO << "日志库设置完毕, 异步线程已启动";
}

/* 初始化数据库连接池 */
void initConnectionPool(ConnectionPool *pool_) {
    pool = pool_;
    LOG_INFO << "数据库连接池设置完毕, 已启动数据库连接池";
}

/*
 * [root@VM-20-11-centos ~]# wrk -t12 -c4000 -d30s http://localhost:8200/sys/login
Running 30s test @ http://localhost:8200/sys/login
  12 threads and 4000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   600.01ms  514.45ms   1.76s    58.65%
    Req/Sec     1.59k     0.96k    8.30k    64.18%
  216530 requests in 30.10s, 29.94MB read
  Socket errors: connect 0, read 0, write 0, timeout 381
Requests/sec:   7194.02
Transfer/sec:      0.99MB
[root@VM-20-11-centos ~]# wrk -t12 -c4000 -d30s http://localhost:8200/login.html
Running 30s test @ http://localhost:8200/login.html
  12 threads and 4000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   370.95ms  357.42ms   2.00s    79.15%
    Req/Sec   472.79    258.70     2.57k    74.04%
  120694 requests in 30.09s, 188.65MB read
  Socket errors: connect 0, read 120694, write 0, timeout 857
Requests/sec:   4010.76
Transfer/sec:      6.27MB
*/